package com.zlyx.easy.access.supports;

import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.List;

import com.zlyx.easy.core.buffer.EasyBuffer;
import com.zlyx.easy.core.loggers.Logger;
import com.zlyx.easy.core.map.EasyMap;
import com.zlyx.easy.core.reflect.FieldMap;
import com.zlyx.easy.core.reflect.FieldUtils;
import com.zlyx.easy.core.tool.StringFormat;
import com.zlyx.easy.core.utils.ObjectUtils;
import com.zlyx.easy.database.enums.SqlType;
import com.zlyx.easy.database.supports.SqlSupport;
import com.zlyx.easy.database.utils.TableUtils;

/**
 * @Auth 赵光
 * @Describle
 * @2019年1月12日 下午6:00:31
 */
public class SqlCreater {

	public static String create(Class<?> tClass, Method method, EasyMap<String, Object> params, SqlType type)
			throws Exception {
		if (params.isEmpty() && SqlType.Select != type) {
			Logger.err(method.getDeclaringClass(), "参数为空");
			return "";
		}
		String methodName = method.getName();
		EasyBuffer eb = EasyBuffer.newBuffer();
		String sql = null;
		if (CurdMethod.insert.equals(methodName)) {
			Object obj = params.getValue("t");
			sql = getBaseSql(SqlType.Insert, tClass);
			eb.append("values (").append(getInsertValues(obj)).append(")");
			sql = sql.replace(SqlSupport.CONTENT, eb.toString());
		} else if (CurdMethod.insertBatch.equals(methodName)) {
			List<?> ts = params.getValue("ts");
			sql = getBaseSql(SqlType.Insert, tClass);
			for (Object obj : ts) {
				eb.append(" select ").append(getInsertValues(obj)).append(" union all");
			}
			sql = sql.replace(SqlSupport.CONTENT, eb.delete(9).toString());
		} else if (CurdMethod.deleteById.equals(methodName)) {
			Object id = params.getValue("id");
			sql = getBaseSql(SqlType.Delete, tClass);
			eb.append(" where id = '").append(id).append("'");
			sql = sql.replace(SqlSupport.CONDITON, eb.toString());
		} else if (CurdMethod.deleteByIds.equals(methodName)) {
			List<Object> ids = params.getValue("ids");
			sql = getBaseSql(SqlType.Delete, tClass);
			eb.append(" where id in (");
			for (Object id : ids) {
				eb.append(" '").append(id).append("',");
			}
			sql = sql.replace(SqlSupport.CONDITON, eb.delete(1).append(")").toString());
		} else if (CurdMethod.updateById.equals(methodName)) {
			Object obj = params.getValue("t");
			sql = getBaseSql(SqlType.Update, tClass);
			sql = sql.replace(SqlSupport.CONTENT, getContent(obj));
			sql = sql.replace(SqlSupport.CONDITON, getUpdateWhere(obj));
		} else if (CurdMethod.updateBatchById.equals(methodName)) {
			List<?> ts = params.getValue("ts");
			for (Object obj : ts) {
				sql = getBaseSql(SqlType.Update, tClass);
				sql = sql.replace(SqlSupport.CONTENT, getContent(obj));
				sql = sql.replace(SqlSupport.CONDITON, getUpdateWhere(obj));
				eb.append(sql).append("; ");
			}
			sql = eb.clearEnd(2);
		} else if (CurdMethod.selectOne.equals(methodName)) {
			sql = getBaseSql(SqlType.Select, tClass);
			sql = sql.replace(SqlSupport.CONDITON, getCondition(tClass, params));
		} else if (CurdMethod.selectList.equals(methodName)) {
			sql = getBaseSql(SqlType.Select, tClass);
			sql = sql.replace(SqlSupport.CONDITON, getCondition(tClass, params));
		} else if (CurdMethod.selectPage.equals(methodName)) {
			sql = getBaseSql(SqlType.Select, tClass);
			sql = sql.replace(SqlSupport.CONDITON, getCondition(tClass, params));
		}
		return sql;
	}

	private static String getCondition(Class<?> tClass, EasyMap<String, Object> params) throws Exception {
		FieldMap mapClass = FieldUtils.getFieldMap(tClass);
		List<String> fieldNames = getFieldNames(mapClass.fields());
		EasyBuffer values = EasyBuffer.newBuffer("where");
		Object value = null;
		for (String fieldName : params.keySet()) {
			value = params.get(fieldName);
			if (fieldNames.contains(fieldName) && ObjectUtils.isNotEmpty(value)) {
				if (ObjectUtils.isNotEmpty(value)) {
					values.append(" ").append(fieldName).append(" = '").append(value).append("',");
				}
			}
		}
		if ("where".equals(values.toString())) {
			return "";
		}
		return values.clearEnd();
	}

	private static String getContent(Object obj) throws Exception {
		FieldMap fieldMap = FieldUtils.getFieldMap(obj.getClass());
		EasyBuffer values = EasyBuffer.newBuffer();
		Field field = null;
		Object value = null;
		for (String name : fieldMap.names()) {
			field = fieldMap.get(name);
			field.setAccessible(true);
			value = field.get(obj);
			if (ObjectUtils.isNotEmpty(value)) {
				values.append(getFieldName(field)).append(" = '").append(value).append("',");
			}
		}
		return values.clearEnd();
	}

	private static String getUpdateWhere(Object obj) throws Exception {
		Field field = FieldUtils.getFieldMap(obj.getClass()).get("id");
		field.setAccessible(true);
		Object value = field.get(obj);
		if (ObjectUtils.isNotEmpty(value)) {
			return EasyBuffer.wrapper("where ", getFieldName(field), "  = '", value, "'");
		}
		return null;
	}

	private static String getInsertValues(Object obj) throws Exception {
		List<Field> fields = FieldUtils.getFieldMap(obj.getClass()).fields();
		EasyBuffer values = EasyBuffer.newBuffer();
		Object value = null;
		for (Field field : fields) {
			field.setAccessible(true);
			value = field.get(obj);
			if (ObjectUtils.isNotEmpty(value)) {
				values.append("'").append(value).append("',");
			} else {
				values.append("null,");
			}
		}
		return values.clearEnd();
	}

	public static String getBaseSql(SqlType type, Class<?> tClass) throws Exception {
		String tableName = tClass.getName();
		FieldMap tableClass = FieldUtils.getFieldMap(tClass);
		switch (type) {
		case Select: {
			return SqlSupport.SELECT.replace("${tableName}", tableName).replace(SqlSupport.RESULTS,
					StringFormat.format(getFieldNames(tableClass.fields())));
		}
		case Update: {
			return SqlSupport.UPDATE.replace("${tableName}", tableName);
		}
		case Insert: {
			return SqlSupport.INSERT.replace("${tableName}", tableName).replace(SqlSupport.NAMES,
					StringFormat.format(tableClass.names().toArray()));
		}
		case Delete: {
			return SqlSupport.DELETE.replace("${tableName}", tableName);
		}
		default: {
			return "";
		}
		}
	}

	public static List<String> getFieldNames(List<Field> fields) throws Exception {
		List<String> list = new ArrayList<>();
		for (Field field : fields) {
			if (!Modifier.isStatic(field.getModifiers()) && field.getType().getName().contains("java")) {
				list.add(getFieldName(field));
			}
		}
		return list;
	}

	public static String getFieldName(Field field) throws Exception {
		return TableUtils.getColumnName(field);
	}
}
